package RSA;

import java.math.BigInteger;
import java.util.Random;

public class KeyPairGenerator{
	
	public static int keyLength = 256;
	private BigInteger m_modulus_n;
	private BigInteger m_exponent_e;
	private BigInteger m_m;
	private BigInteger m_exponent_u;
	private static final Random rnd = new Random();
	
	
	public KeyPairGenerator(int kl)
	{
		keyLength = kl;
		
		BigInteger p,q;
		p=BigInteger.probablePrime(keyLength/2, rnd);
		
		q=BigInteger.probablePrime(keyLength/2, rnd);
		
		if(p.equals(q)) q=BigInteger.probablePrime(keyLength, rnd);
		
		m_modulus_n = p.multiply(q);
		
		m_m=p.subtract(new BigInteger("1")).multiply(q.subtract(new BigInteger("1")));
		
		m_exponent_e = generateExponent(m_m);
	
		m_exponent_u = euclide(m_exponent_e, m_m);
		
	}
	
	public Key getPublicKey()
	{
		return new Key(m_modulus_n, m_exponent_e, keyLength);
	}
	
	public Key getPrivateKey()
	{
		return new Key(m_modulus_n, m_exponent_u, keyLength);
	}

	
	private BigInteger generateExponent(BigInteger m) {
		
		Random rnd = new Random();
		BigInteger e = new BigInteger(m.bitLength(), rnd);
		if(e.mod(BigInteger.valueOf(2)).equals(BigInteger.valueOf(1)) && m.gcd(e).equals(BigInteger.ONE)) return e;
		else return generateExponent(m);
		
	}

	
	private BigInteger euclide(BigInteger b, BigInteger n)
	{
	    BigInteger N = n;
	    BigInteger B = b;
	    BigInteger t0 = BigInteger.ZERO;
	    BigInteger t = BigInteger.ONE;
	    BigInteger q = N.divide(B);
	    BigInteger r = N.subtract(q.multiply(B));
	    BigInteger temp = BigInteger.ZERO;
	    while(r.compareTo(BigInteger.ZERO)>0)
	    {
	        temp = t0.subtract(q.multiply(t));
	        if(temp.compareTo(BigInteger.ZERO)>=0)
	        {
	            temp = temp.mod(n);
	        }
	        else
	        {
	            temp = n.subtract(temp.negate().mod(n));
	        }
	        t0 = t;
	        t = temp;
	        N = B;
	        B = r;
	        q = N.divide(B);   
	        r = N.subtract(q.multiply(B));
	    }
	    if(!B.equals(BigInteger.ONE))
	    {
	        System.out.println("b n'a pas d'inverse modulo n");
	    }
	    else
	    {
	        //System.out.println("Nombre d'itération de l'algorithme d'euclide = "+t);
	        return t;
	    	//return b.modInverse(n);
	    }
	    
	    return b;
	}

	

}
